//
//  PathGrid.cpp
//  IsoCplus
//
//  Created by 周张林 on 15/9/15.
//
//

#include "PathGrid.h"

bool PathGrid::init(int gridX,int gridZ)
{
    if(!_nodes.empty()) return false;
    
    _gridX = gridX;
    _gridZ = gridZ;
    for(auto i=0;i<gridX;i++){
        std::vector<PathNode*> v;
        for(auto j=0;j<gridZ;j++){
            auto node = new PathNode();
            node->init(i, j);
            v.push_back(node);
        }
        _nodes.push_back(v);
    }
    return true;
}

PathGrid::~PathGrid()
{
    for(auto i=0;i<_gridX;i++){
        for(auto j=0;j<_gridZ;j++){
            delete _nodes[i][j];
            _nodes[i][j] = nullptr;
        }
    }
    _nodes.clear();
    if(_startNode!=nullptr){
        _startNode = nullptr;
    }
    if(_endNode!=nullptr){
        _endNode = nullptr;
    }
}

void PathGrid::setAllWalkable(bool value)
{
    for(auto i=0;i<_gridX;i++){
        for(auto j=0;j<_gridZ;j++){
            _nodes[i][j]->walkable = value;
        }
    }
}

void PathGrid::changeSize(int gridX,int gridZ)
{
    if(_gridX!=gridX || _gridZ!=gridZ){
        std::vector<std::vector<PathNode*>> nodes;
        for(auto i=0;i<gridX;i++){
            std::vector<PathNode*> v;
            for(auto j=0;j<gridZ;j++){
                if (i<_gridX && j<_gridZ)
                {
                    v[j] = _nodes[i][j];
                }
                else
                {
                    auto node = new PathNode();
                    node->init(i, j);
                    v[j] = node;
                }
            }
            nodes.push_back(v);
        }
        //clear
        for(auto i=0;i<_gridX;i++){
            for(auto j=0;j<_gridZ;j++){
                if(i>=gridX || j>=gridZ){
                    delete _nodes[i][j];
                    _nodes[i][j] = nullptr;
                }
            }
        }
        _nodes.clear();
        _gridX = gridX;
        _gridZ = gridZ;
        _nodes = nodes;
    }
}


const std::vector<PathNode*> &PathGrid::getNodesByWalkable(bool walkable)
{
    _walkableNodes.clear();
    for(auto i=0;i<_gridX;i++){
        for(auto j=0;j<_gridZ;j++){
            if(_nodes[i][j]->walkable==walkable) {
                _walkableNodes.push_back( _nodes[i][j]);
            }
        }
    }
    return _walkableNodes;
}

void PathGrid::initNodeLink(PathNode *node, int type)
{
    auto startX = std::max<float>(0, node->x - 1);
    auto endX = std::min<float>(_gridZ - 1, node->x + 1);
    auto startY = std::max<float>(0, node->y - 1);
    auto endY = std::min<float>(_gridX - 1, node->y + 1);
    
    for (auto &link : node->links) {
        delete link;
        link = nullptr;
    }
    node->links.clear();
    
    for (auto i = startX; i < endX; i++){
        for (auto j = startY; j < endY; j++){
            auto test = getNode(i, j);
            if ( test == node || !test->walkable){
                continue;
            }
            if (type != 2 && i != node->x && j != node->y){
                auto test2 = getNode(node->x, j);
                if (!test2->walkable){
                    continue;
                }
                test2 = getNode(i, node->y);
                if (!test2->walkable){
                    continue;
                }
            }
            auto cost = _straightCost;
            if (!((node->x == test->x) || (node->y == test->y))){
                if (type == 1){
                    continue;
                }
                if (type == 2 && (node->x - test->x) * (node->y - test->y) == 1){
                    continue;
                }
                if (type == 2){
                    cost = _straightCost;
                } else {
                    cost = _diagCost;
                }
            }
            PathLink *link = new PathLink();
            link->init(test, cost);
            node->links.push_back(link);
        }
    }
}


bool PathGrid::checkInGrid(int nodeX,int nodeZ) const
{
    if(nodeX<0 || nodeZ<0 || nodeX>=_gridX || nodeZ>=_gridZ) return false;
    return true;
}


PathNode* PathGrid::getNode(int nodeX,int nodeZ) const
{
    return _nodes[nodeX][nodeZ];
}


void PathGrid::setStartNode(int nodeX,int nodeZ)
{
     _startNode = _nodes[nodeX][nodeZ];
}

PathNode* PathGrid::getStartNode() const
{
    return _startNode;
}

void PathGrid::setEndNode(int nodeX,int nodeZ)
{
    _endNode = _nodes[nodeX][nodeZ];
}

PathNode* PathGrid::getEndNode() const
{
    return _endNode;
}


void PathGrid::setWalkable(int nodeX,int NodeZ, bool value)
{
        _nodes[nodeX][NodeZ]->walkable=value;
}

void PathGrid::calculateLinks(int type)
{
    _type = type;
    for (auto i = 0; i < _gridX; ++i ){
        for (auto j = 0; j < _gridZ; ++j){
            initNodeLink( _nodes[i][j], _type);
        }
    }
}
int PathGrid::getType() const
{
    return _type;
}
int PathGrid::getGridX() const
{
    return _gridX;
}
int PathGrid::getGridZ() const
{
    return _gridZ;
}